package com.nearbymap.model;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class PlacesResponse {
	public static final String XPATH_PLACES_NODES = "PlaceSearchResponse/result";
	private static Logger logger = Logger.getLogger(PlacesResponse.class.getName());
	private XmlResponse xmlResponse;
	private XPath xpath = XPathFactory.newInstance().newXPath();

	public PlacesResponse() {
		xmlResponse = new XmlResponse();
	}
	public PlacesResponse(String responseXml) {
		xmlResponse = new XmlResponse();
		xmlResponse.setResponseXml(responseXml);
	}
	public PlacesResponse(XmlResponse xmlResponse) {
		this.xmlResponse = xmlResponse;
	}
	
	public List<Place> getPlaces() {
		NodeList nodes = this.xmlResponse.getNodes(XPATH_PLACES_NODES);
		logger.fine("nodes Length: " + nodes.getLength());
		List<Place> places = new ArrayList<Place>();
		for (int i = 0; i < nodes.getLength(); i++) {
			Node result = nodes.item(i);
			Place place = new Place();
			try {
				NodeList nameNode = (NodeList) xpath.evaluate("name", result, XPathConstants.NODESET);
				if(nameNode.getLength() == 1) {
					place.setName(nameNode.item(0).getTextContent());
					logger.fine("Place name: " + place.getName());
				} else {
					throw new RuntimeException("Bad name size: " + nameNode.getLength());
				}

				NodeList vicinityNode = (NodeList) xpath.evaluate("vicinity", result, XPathConstants.NODESET);
				if(vicinityNode.getLength() == 1) {
					place.setVicinity(vicinityNode.item(0).getTextContent());
					logger.fine("Place vicinity: " + place.getVicinity());
				} else {
					throw new RuntimeException("Bad vicinity size: " + vicinityNode.getLength());
				}

				NodeList typeNodes = (NodeList) xpath.evaluate("type", result, XPathConstants.NODESET);
				List<String> typeList = new ArrayList<String>();
				for (int j = 0; j < typeNodes.getLength(); j++) {
					String type = typeNodes.item(j).getTextContent();
					typeList.add(type);
					logger.fine("Place type: " + type);
				}
				place.setTypes(typeList);
				logger.fine("Place type: " + place.getTypes());

				NodeList latNode = (NodeList) xpath.evaluate("geometry/location/lat", result, XPathConstants.NODESET);
				NodeList lngNode = (NodeList) xpath.evaluate("geometry/location/lng", result, XPathConstants.NODESET);
				if(latNode.getLength() == 1 && lngNode.getLength() == 1) {
					double lat = Double.parseDouble(latNode.item(0).getTextContent());
					double lng = Double.parseDouble(lngNode.item(0).getTextContent());
					place.setLocation(new LatLng(lat,lng));
					logger.fine("Place latLng: " + place.getLocation());
				} else {
					throw new RuntimeException("Bad latL size: " + latNode.getLength() + " or lng size: " + latNode.getLength());
				}
				NodeList iconNode = (NodeList) xpath.evaluate("icon", result, XPathConstants.NODESET);
				if(iconNode.getLength() == 1) {
					place.setIconUrl(iconNode.item(0).getTextContent());
					logger.fine("Place icon: " + place.getIconUrl());
				} else {
					throw new RuntimeException("Bad icon size: " + iconNode.getLength());
				}
				NodeList referenceNode = (NodeList) xpath.evaluate("reference", result, XPathConstants.NODESET);
				if(referenceNode.getLength() == 1) {
					place.setReference(referenceNode.item(0).getTextContent());
					logger.fine("Place reference: " + place.getReference());
				} else {
					throw new RuntimeException("Bad reference size: " + referenceNode.getLength());
				}
				NodeList idNode = (NodeList) xpath.evaluate("id", result, XPathConstants.NODESET);
				if(idNode.getLength() == 1) {
					place.setId(idNode.item(0).getTextContent());
					logger.fine("Place id: " + place.getId());
				} else {
					throw new RuntimeException("Bad id size: " + idNode.getLength());
				}
				places.add(place);
			} catch (XPathExpressionException e) {
				e.printStackTrace();
				throw new RuntimeException(e.getMessage(), e);
			} catch (DOMException e) {
				e.printStackTrace();
				throw new RuntimeException(e.getMessage(), e);
			}
			
			
/*			for (int j = 0; j < result.getChildNodes().getLength(); j++) {
				Node node = result.getChildNodes().item(j);
				NamedNodeMap a = node.getAttributes();
				logger.fine("Attributes: " + a);
				String b = node.getNodeName();
				logger.fine("Name: " + b);
				short c = node.getNodeType();
				logger.fine("Type: " + c);
				String d = node.getNodeValue();
				logger.fine("Value: " + d);
				NodeList childNodes = node.getChildNodes();
				logger.fine("ChildNodes Length: " + childNodes.getLength());
			}*/
		}
		
		return places;
	}

	public NodeList getPlacesNodes() {
		return this.xmlResponse.getNodes(XPATH_PLACES_NODES);
	}

	public List<String> getTextAt(String xpathPattern) {
		return this.xmlResponse.getTextAt(xpathPattern);
	}

	public void setResponseXml(String responseXml) {
		this.xmlResponse.setResponseXml(responseXml);
	}
}
